package com.haoran.dwz.web;

import java.math.BigDecimal;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import com.haoran.dwz.common.exception.NoExistException;
import com.haoran.dwz.common.exception.ParseShortURLException;
import com.haoran.dwz.common.exception.ValidException;
import com.haoran.dwz.common.redis.RedisSequenceWorker;
import com.haoran.dwz.common.redis.RedisSequenceWorker.SequenceType;
import com.haoran.dwz.common.security.UsmContextHolder;
import com.haoran.dwz.common.util.DisorderedCompressEncoder;
import com.haoran.dwz.common.util.SnowflakeIdWorker;
import com.haoran.dwz.common.util.Validator;
import com.haoran.dwz.domain.entities.ShortURL;
import com.haoran.dwz.rest.R;
import com.haoran.dwz.service.ShortUrlService;
import com.haoran.dwz.wrapper.PaginationWrapper;

import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;

@Controller
@RequestMapping(value = "short-url", produces = "application/json;charset=UTF-8")
public class URLController {

	private Logger logger = LoggerFactory.getLogger(getClass());
	
	private static final int MAX_LENGTH = 5;

	private SnowflakeIdWorker idWorker = new SnowflakeIdWorker(0);

	@Autowired
	private ShortUrlService shortURLService;
	
	@Autowired
	private RedisSequenceWorker redisSequenceWorker;

//	@ApiOperation("生成短链接记录接口 类snake算法生成")
//	@RequestMapping(value = "generate", method = RequestMethod.POST)
//	@ResponseBody
	@Deprecated
	public R generate(@ApiParam(value = "原始URL地址", required = true) @RequestParam String URL) {
		if (StringUtils.isBlank(URL) || !Validator.isUrl(URL)) {
			return R.failure(new ValidException("请输入正确的URL地址!"));
		}
		ShortURL entity = new ShortURL();
		entity.setUrl(StringUtils.trim(URL));
		ShortURL shortUrl = shortURLService.findByUrl(URL);
		if(shortUrl != null) {
			shortUrl.setExpireTime(oneYearLater());
			shortURLService.save(shortUrl);
			return R.success(shortUrl.getDwz());
		}
		long nextId = idWorker.nextId();
		String id = DisorderedCompressEncoder.compressNumber(nextId);
		while(shortURLService.exists(nextId)) {
			nextId = idWorker.nextId();
			id = DisorderedCompressEncoder.compressNumber(nextId);
			if(id.length() > MAX_LENGTH) {
				Calendar epoch = Calendar.getInstance();
				epoch.add(Calendar.MONTH, 3);
				idWorker.setTwepoch(epoch.getTime().getTime());
				nextId = idWorker.nextId();
				id = DisorderedCompressEncoder.compressNumber(nextId);
			}
		}
		entity.setId(nextId);
		Calendar instance = Calendar.getInstance();
		entity.setCreateTime(instance.getTime());
		instance.add(Calendar.DAY_OF_MONTH, 30);
		entity.setExpireTime(instance.getTime());
		ShortURL save = shortURLService.save(entity);
		return R.success(save.getDwz());
	}

	@ApiOperation("生成短链接记录接口")
	@RequestMapping(value = "generate", method = RequestMethod.POST)
	@ResponseBody
	public R generate(@ApiParam(value = "原始URL地址", required = true) @RequestParam String URL,@ApiParam(value = "短网址类型", required = true) @RequestParam int type) {
		if (StringUtils.isBlank(URL) || !Validator.isUrl(URL)) {
			return R.failure(new ValidException("请输入正确的URL地址!"));
		}
		SequenceType valueOfType = SequenceType.valueOfType(type);
		if(valueOfType == null) {
			return R.failure(new ValidException("请输入 1 到 5 之间的整数"));
		}
		ShortURL entity = new ShortURL();
		entity.setUrl(StringUtils.trim(URL));
		ShortURL shortUrl = shortURLService.findByUrl(URL);
		if(shortUrl != null) {
			shortUrl.setExpireTime(oneYearLater());
			shortURLService.save(shortUrl);
			return R.success(shortUrl.getDwz());
		}
		long nextId = redisSequenceWorker.generateId(valueOfType);
		while(shortURLService.exists(nextId)) {
			ShortURL s = shortURLService.findOne(nextId);
			if(s.getExpireTime().before(now())) {
				s.setExpireTime(oneYearLater());
				s.setUrl(URL);
				shortURLService.save(s);
				return R.success(s.getDwz());
			}
			logger.error("Id:" +  nextId + " 生成失败了 重新再生成");
			nextId = redisSequenceWorker.generateId(valueOfType);
		}
		entity.setId(nextId);
		entity.setDwz(ShortUrlService.DWZ_ADDRESS+DisorderedCompressEncoder.compressNumber(nextId));
		entity.setCreateTime(now());
		entity.setExpireTime(oneYearLater());
		ShortURL save = shortURLService.save(entity);
		return R.success(save.getDwz());
	}

	/**
	 * 一年以后
	 * @return
	 */
	private Date oneYearLater() {
		Calendar instance = Calendar.getInstance();
		instance.add(Calendar.YEAR, 1);
		return instance.getTime();
	}
	
	/**
	 * 一年以后
	 * @return
	 */
	private Date now() {
		Calendar instance = Calendar.getInstance();
		return instance.getTime();
	}

	@ApiOperation("短链接转换成长链接接口")
	@RequestMapping(value = "parse", method = RequestMethod.GET)
	@ResponseBody
	public R parse(@ApiParam(value = "短链接地址", required = true) @RequestParam String shortURL) {
		if (StringUtils.isBlank(shortURL) || !shortURL.startsWith(ShortUrlService.DWZ_ADDRESS)) {
			return R.failure(new ParseShortURLException("请输入以: " + ShortUrlService.DWZ_ADDRESS + " 前缀的短链接"));
		}
		String id = shortURL.substring(ShortUrlService.DWZ_ADDRESS.length());
		ShortURL save = shortURLService.findOne(DisorderedCompressEncoder.unCompressNumber(id));
		if (save != null) {
			save.setLastUsedTime(now());
			save.setExpireTime(oneYearLater());
			shortURLService.save(save);
			return R.success(save.getUrl());
		} else {
			return R.failure(new NoExistException("该短链接已经失效或不存在!"));
		}
	}

	@ApiOperation("查询所有的短链接记录")
	@RequestMapping(value = "list", method = RequestMethod.GET)
	@ResponseBody
	public R list() {
		List<ShortURL> list = shortURLService.findAll();
		return R.success(list);
	}

	@ApiOperation("删除短链接记录")
	@RequestMapping(value = "remove", method = RequestMethod.POST)
	@ResponseBody
	public R delete(@RequestParam("ids[]") long[] ids) {
		if (ids == null || ids.length == 0) {
			return R.success();
		} else {
			for (long id : ids) {
				if (shortURLService.exists(id)) {
					shortURLService.delete(id,UsmContextHolder.getUser().getUsername());
				}
			}
			return R.success();
		}
	}

	@ApiOperation("分页查询所有的短链接记录")
	@RequestMapping(value = "page-list", method = { RequestMethod.GET })
	@ResponseBody
	public PaginationWrapper findByPageable(ShortURL shortURL) {
		Sort sort;
		if(StringUtils.isNotBlank(shortURL.getSidx()) && StringUtils.isNotBlank(shortURL.getOrder())){
			sort = new Sort(shortURL.getDirection(), shortURL.getSidx());
		}else{
			sort = new Sort(Direction.ASC, "lastUsedTime", "createTime");
		}
		Pageable pageable = new PageRequest(shortURL.getPage()-1, shortURL.getLimit(), sort);
		Page<ShortURL> entryByPageable = shortURLService.findByPageable(shortURL,pageable);
		PaginationWrapper pageUtil = new PaginationWrapper(entryByPageable.getContent(), entryByPageable.getTotalElements(), shortURL.getLimit(),	shortURL.getPage());
		return pageUtil;
	}

	@ApiOperation(value = "跳转页", hidden = true)
	@RequestMapping(value = "/index", method = { RequestMethod.GET })
	public String index(Model model) {
		return "url/shorturl";
	}
	
	@ApiOperation(value = "查询使用率")
	@RequestMapping(value = "/used-rate", method = { RequestMethod.GET })
	@ResponseBody
	public R usedRate(@RequestParam int type) {
		SequenceType valueOfType = SequenceType.valueOfType(type);
		if(valueOfType ==null)
		{
			R.failure(new ValidException("无效的短网址类型!"));
		}
		BigDecimal currentUsedRate = redisSequenceWorker.currentUsedRate(valueOfType);
		logger.info("当前" + valueOfType + "的使用率是:" +  currentUsedRate.toString());
		return R.success(currentUsedRate.toString());
	}
	
	@ApiOperation(value = "查询使用率",hidden=true)
	@RequestMapping(value = "/all-rates", method = { RequestMethod.GET })
	@ResponseBody
	public R allRates() {
		Map<String,String> map = new HashMap<>();
		for (SequenceType sequenceType : SequenceType.values()) {
			BigDecimal currentUsedRate = redisSequenceWorker.currentUsedRate(sequenceType);
			logger.info("当前" + sequenceType.name() + "的使用率是:" +  currentUsedRate.toString());
			map.put(sequenceType.name(), currentUsedRate.toString());
		}
		return R.success(map);
	}
	
	@ApiOperation(value = "查询使用率",hidden=true)
	@RequestMapping(value = "/total-rates", method = { RequestMethod.GET })
	@ResponseBody
	public R totalRates() {
		Map<String,String> map = new HashMap<>();
		map.put("totalRate", redisSequenceWorker.currentUsedRate().toString());
		return R.success(map);
	}
}
